package cloudspace.demo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

import org.zkoss.zhtml.A;
import org.zkoss.zhtml.Div;
import org.zkoss.zhtml.Text;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.util.GenericComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;
import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Toolbarbutton;

import cloudspace.vm.VM;


public class WorkspaceController extends GenericComposer
{
    private Borderlayout self;

    private List<A> buttons = new ArrayList<A>();
    private Textbox zhtmlCodeBox;
    private Textbox javaCodeBox;

    /**
     * 
     */
    private static final long serialVersionUID = -7078148059136508558L;


    // private Map<A, Integer> buttonOrderMap = new HashMap<A, Integer>();

    private class ButtonSorter implements Comparator<A>
    {

        public int compare( A arg0, A arg1 )
        {
            Integer val0 = (Integer)arg0.getAttribute( "priority" );
            Integer val1 = (Integer)arg1.getAttribute( "priority" );
            if ( val0 < val1 )
                return -1;
            else if ( val0 > val1 )
                return 1;
            return 0;
        }

    }


    private class LoadDemoListener implements EventListener
    {
        private String demoName;


        public LoadDemoListener( String demoName )
        {
            this.demoName = demoName;
        }


        public void onEvent( Event event ) throws Exception
        {
            setupPage( (A)event.getTarget() );

        }

    }


    private String getFileContent( String fileName ) throws IOException
    {
        VM current = VM.lookupVM();
        File demoFolder = new File( current.getLocalRoot() + "/demos/"
            + fileName );
        BufferedReader reader = new BufferedReader( new FileReader( demoFolder ) );
        String line = reader.readLine();
        String result = "";
        while ( line != null )
        {
            result += line + "\n";
            line = reader.readLine();
        }
        reader.close();
        return result;
    }


    private void setupPage( A button )
    {
//        A button = (A)self.getFellow( "button_" + demoName );
        for ( A link : buttons )
            link.setSclass( "" );
        button.setSclass( "here" );
        zhtmlCodeBox.setValue( "" );
        javaCodeBox.setValue( "" );
        setupInstructions( button );
        setupCode( button );
        setupLayout( button );
    }


    public void updateCode( String javaCode )
    {
        self.getPage()
            .getInterpreter( "java" )
            .interpret( javaCode, self.getPage() );

    }


    private void setupCode( A button )
    {
        try
        {
            Div view = (Div)self.getFellow( "view" );
            Components.removeAllChildren( view );
            String javaCode = getFileContent( button.getAttribute( "dirName" )
                + "/code.txt" );
            updateCode( javaCode );
            ((Textbox)self.getFellow( "javaCode" )).setValue(javaCode);
        }
        catch ( IOException e )
        {
            throw new UiException( "Could not build code page", e );
        }
    }


    private void setupInstructions( A button )
    {
        try
        {
            Div instructDiv = (Div)self.getFellow( "instructDiv" );
            Components.removeAllChildren( instructDiv );
//            A button = (A)self.getFellow( "button_" + demoName );
            String instructions = getFileContent( button.getAttribute( "dirName" )
                + "/instructions.zhtml" );
            Executions.createComponentsDirectly( "<zk>" + instructions
                + "</zk>", "zhtml", instructDiv, null );
        }
        catch ( IOException e )
        {
            throw new UiException( "Could not build instructions pane", e );
        }
    }

    public void updateLayout( String zhtmlCode )
    {
        Div view = (Div)self.getFellow( "view" );
        Components.removeAllChildren( view );
        java.util.regex.Matcher m = java.util.regex.Pattern.compile( "<variable[^>]*name=(\"([^\">]*)\"|'([^'>]*)')" )
            .matcher( zhtmlCode );
        while ( m.find() )
        {
            String var = m.group( 2 );
            if ( var == null )
            {
                var = m.group( 3 );
            }
            if ( var != null )
            {
                self.getPage().getInterpreter( "java" ).unsetVariable( var );
            }
        }

        Executions.createComponentsDirectly( "<zk>" + zhtmlCode + "</zk>",
            "zhtml",
            view,
            null );
        AnnotateDataBinder binder = new AnnotateDataBinder( self.getPage(),
            true );
        self.getPage().setAttribute( "binder", binder );
        binder.loadAll();

    }


    private void setupLayout( A button )
    {
        try
        {
            String zhtmlCode = getFileContent( button.getAttribute( "dirName" )
                + "/ui.zhtml" );
            updateLayout( zhtmlCode );
            Textbox zhtmlCodeBox = (Textbox)self.getFellow( "zhtmlCode" );
            zhtmlCodeBox.setValue( zhtmlCode );
        }
        catch ( IOException e )
        {
            throw new UiException( "Could not build the zhtml viewing div", e );
        }
    }


    public void doAfterCompose( Component div )
    {
        self = (Borderlayout)div;
        zhtmlCodeBox = (Textbox)self.getFellow( "zhtmlCode" );
        javaCodeBox = (Textbox)self.getFellow( "javaCode" );
        Div buttonDiv = (Div)self.getFellow( "buttonDiv" );
        VM current = VM.lookupVM();
        File demoFolder = new File( current.getLocalRoot() + "/demos/" );
        File[] demos = demoFolder.listFiles();
        if ( demos == null )
            throw new RuntimeException( "You must have a /demos/ directory!" );
        if ( demos.length == 0 )
            return;
        PriorityQueue<A> buttonSorter = new PriorityQueue<A>( demos.length, new ButtonSorter() );
        for ( int i = 0; i < demos.length; i++ )
        {
            String demoName = demos[i].getName();
            String[] parts = demoName.split( "-" );
            int priority = Integer.parseInt( parts[0] );
            A button = new A();
            button.setAttribute( "priority", priority );

            button.setDynamicProperty( "href", "" );

            button.setAttribute( "dirName", demoName );
            button.setId( "button_" + parts[1] );
            button.addEventListener( "onClick", new LoadDemoListener( parts[1] ) );
            Text buttonLabel = new Text( parts[1] );
            button.appendChild( buttonLabel );
            buttonSorter.add( button );
        }
        while(!buttonSorter.isEmpty())
            buttons.add(buttonSorter.remove());
        for ( A button : buttons )
            buttonDiv.appendChild( button );

        setupPage( buttons.get( 0 ) );
        Toolbarbutton layoutApply = (Toolbarbutton)self.getFellow( "zhtmlApply" );
        layoutApply.addEventListener( "onClick",new EventListener(){

            public void onEvent( Event event ) throws Exception
            {
                updateLayout(zhtmlCodeBox.getValue());
                
            }
            
        });
        Toolbarbutton codeApply = (Toolbarbutton)self.getFellow( "codeApply" );
        codeApply.addEventListener( "onClick",new EventListener(){

            public void onEvent( Event event ) throws Exception
            {
                updateCode(javaCodeBox.getValue());
                updateLayout(zhtmlCodeBox.getValue());
                
            }
            
        });
    }
}
